package com.bigflexlib.x.mx.controls.sliderClasses.Slider
{
	
	
	import com.bigflexlib.utils.AbstractOperator;
	import com.bigflexlib.x.flash.geom.Point.PointUtil;
	import com.bigflexlib.x.mx.core.Application.App;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.geom.Point;
	
	import mx.binding.utils.BindingUtils;
	import mx.binding.utils.ChangeWatcher;
	import mx.controls.sliderClasses.Slider;



	/**
	 * 
	 * Assumptions:
	 * - the model is the display object
	 * - scaling is regular ( scaleX == scaleY )
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class SliderZoomingOp extends AbstractOperator
	{
		
		
		
		private var slider:Slider;
		
		private var target:DisplayObject;
		
		private var autoCenterInParent:Boolean;
		
		
		
		
		private var slh:ScaleLinearizerHelper;
		
		

		private var sliderDiff:Number;
		


		private var sliderChangeWatcher:ChangeWatcher;
		
		
		
		// flags so we don't run into infinite recursion
		private var updatingSliderFlag:Boolean = false;
		private var updatingTargetFlag:Boolean = false;
		
		
		
		private var lastTargetScale:Number;
		
		
		
		
		/**
		 * 
		 * @param slider
		 * @param target
		 * @param minScale
		 * @param maxScale
		 * 
		 */		
		public function SliderZoomingOp( slider:Slider, target:DisplayObject, minScale:Number, maxScale:Number, autoCenterInParent:Boolean )
		{
			
			// store member vars
			
			
			this.slider 				= slider;
			this.target 				= target;
			this.autoCenterInParent 	= autoCenterInParent;
			
			
			// some calculations
			
			this.slh = new ScaleLinearizerHelper( minScale, maxScale );
			this.sliderDiff = slider.maximum - slider.minimum;
			

			// kick off event listeners

			
				// listen to changes on the target
			
			App.app.addEventListener( Event.ENTER_FRAME, app_enterFrame );


				// listen to changes on the slider

			sliderChangeWatcher = BindingUtils.bindSetter( slider_value_changed, slider, "value", false );
			
									
		}
		
		
		
		
		private function getCenterInParent( ):Point
		{
			var p:DisplayObject = target.parent;
			return new Point( p.width/2, p.height/2 );
		}
		
		
		
		
		
		private function value2scale( value:Number ):Number
		{
			var point:Number = ( value - slider.minimum ) / sliderDiff;
			return slh.scaleForPoint( point );
		}
		
		

		private function scale2value( scale:Number ):Number
		{
			var point:Number = slh.pointForScale( scale );
			return slider.minimum + ( point * sliderDiff );
		}
		
		
		
		private function app_enterFrame( event:Event ):void
		{

			var scale:Number = target.scaleX;
			if ( scale == lastTargetScale )		
				return;
				
			lastTargetScale = scale;
			
			updatingSliderFlag = true;
				slider.value = scale2value( scale );	
			updatingSliderFlag = false;	
		}




		private function slider_value_changed( value:Number ):void
		{
		
			if ( updatingSliderFlag )
				return;
				
			updatingTargetFlag = true;

				var scale:Number = value2scale( value );

				if ( !autoCenterInParent )
				{
					target.scaleX = scale;
					target.scaleY = scale;
				}
				else
				{
					var centerInParent:Point = getCenterInParent( );
					// trace( "cip = " + centerInParent );
					// get coords before rescaling
					var centerInTarget			:Point = PointUtil.lgl( centerInParent, target.parent, target );

					target.scaleX = scale;
					target.scaleY = scale;
					
					var centerInParentAfter		:Point = PointUtil.lgl( centerInTarget, target, target.parent );
					
					// how much did the center move in the parent coordinate space?
					var diff:Point = centerInParent.subtract( centerInParentAfter );
					
					// correction
					target.x += diff.x;
					target.y += diff.y;
					
					// trace( " - " + diff );
					
				}






			updatingTargetFlag = false;
		
		}





		
		
		override public function dispose( ):void
		{
			
			super.dispose( );
			
			App.app.removeEventListener( Event.ENTER_FRAME, app_enterFrame );
		
			sliderChangeWatcher.unwatch( );
		
		}
				
		

	}

}